<template>
  <div class="component-upload-media">
    <!-- 图片上传区域 -->
    <div class="upload-area">
      <el-button 
        size="small" 
        type="primary" 
        @click="triggerImageUpload"
        :disabled="disabled || imageList.length >= imageLimit"
      >
        上传图片
      </el-button>
      <input 
        type="file" 
        ref="imageInput" 
        style="display: none" 
        accept="image/*" 
        @change="handleImageChange"
      >
      <div class="el-upload__tip" v-if="showTip && !disabled">
        可上传{{imageLimit}}张图片，单张不超过{{ fileSize }}MB，支持{{ imageFileType.join('/') }}格式
      </div>
    </div>

    <!-- 图片列表展示 -->
    <div class="image-list">
      <div v-for="(item, index) in imageList" :key="item.url" class="image-item">
        <img :src="item.url" @click="handlePictureCardPreview(item)">
        <div class="image-actions">
          <div @click.stop="handleDelete(item, 'image')"><el-icon class="el-icon-delete"></el-icon></div>
          <span v-if="item.status === 'uploading'" class="upload-progress">上传中...</span>
        </div>
      </div>
    </div>

    <!-- 视频上传区域 -->
    <div class="upload-area" style="margin-top: 20px">
      <el-button 
        size="small" 
        type="primary" 
        @click="triggerVideoUpload"
        :disabled="disabled || videoList.length >= videoLimit"
      >
        上传视频
      </el-button>
      <input 
        type="file" 
        ref="videoInput" 
        style="display: none" 
        multiple
        accept="video/*" 
        @change="handleVideoChange"
      >
      <div class="el-upload__tip" v-if="showTip && !disabled">
        可上传{{videoLimit}}个视频，单个不超过{{ videoSize }}MB，支持{{ videoFileType.join('/') }}格式
      </div>
    </div>

    <!-- 视频列表展示 -->
    <div class="video-list">
      <div v-for="(item, index) in videoList" :key="item.url" class="video-item">
        <video :src="item.url" controls></video>
        <div class="video-actions">
          <div @click.stop="handleDelete(item, 'video')"><el-icon class="el-icon-delete"></el-icon></div>
          <span v-if="item.status === 'uploading'" class="upload-progress">上传中...</span>
        </div>
      </div>
    </div>

    <!-- 图片预览对话框 -->
    <el-dialog :visible.sync="imageDialogVisible" title="图片预览" width="800" append-to-body>
      <img :src="dialogImageUrl" style="display: block; max-width: 100%; margin: 0 auto" />
    </el-dialog>
  </div>
</template>

<script>
import { getToken } from "@/utils/auth"
import { isExternal } from "@/utils/validate"
import request from '@/utils/request'

export default {
  name: 'MediaUpload',
  props: {
    value: {
      type: [String, Object, Array],
      default: () => ({ images: [], videos: [] })
    },
    // 上传接口地址
    action: {
      type: String,
      default: "/common/upload"
    },
    // 图片数量限制
    imageLimit: {
      type: Number,
      default: 5
    },
    // 视频数量限制
    videoLimit: {
      type: Number,
      default: 5
    },
    // 图片大小限制(MB)
    fileSize: {
      type: Number,
      default: 2
    },
    // 视频大小限制(MB)
    videoSize: {
      type: Number,
      default: 50
    },
    // 上传携带的参数
    data: {
      type: Object,
      default: () => ({})
    },
    // 图片文件类型
    imageFileType: {
      type: Array,
      default: () => ["png", "jpg", "jpeg", "gif"]
    },
    // 视频文件类型
    videoFileType: {
      type: Array,
      default: () => ["mp4", "avi", "mov"]
    },
    // 是否显示提示
    isShowTip: {
      type: Boolean,
      default: true
    },
    // 是否禁用
    disabled: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      baseUrl: process.env.VUE_APP_BASE_API,
      imageList: [],
      videoList: [],
      imageDialogVisible: false,
      dialogImageUrl: "",
      uploadingCount: 0 // 正在上传的文件数量
    }
  },
  computed: {
    showTip() {
      return this.isShowTip
    },
    isUploading() {
      return this.uploadingCount > 0
    }
  },
  watch: {
    value: {
      handler(val) {
        if (val) {
          this.parseValue(val)
        } else {
          this.imageList = []
          this.videoList = []
        }
      },
      immediate: true
    }
  },
  methods: {
    // 解析初始值
    parseValue(val) {
      if (typeof val === 'string') {
        try {
          val = JSON.parse(val)
        } catch {
          val = { images: [], videos: [] }
        }
      }
      
      this.imageList = Array.isArray(val.images) ? 
        this.normalizeFileList(val.images) : 
        this.normalizeFileList(val.images?.split(',') || [])
        
      this.videoList = Array.isArray(val.videos) ? 
        this.normalizeFileList(val.videos) : 
        this.normalizeFileList(val.videos?.split(',') || [])
    },
    
    // 标准化文件列表
    normalizeFileList(list) {
      return list.map(item => {
        if (typeof item === 'string') {
          if (item.indexOf(this.baseUrl) === -1 && !isExternal(item)) {
            return { 
              name: item, 
              url: this.baseUrl + item,
              status: 'success'
            }
          }
          return { 
            name: item, 
            url: item,
            status: 'success'
          }
        }
        return item
      })
    },
    
    // 触发图片上传
    triggerImageUpload() {
      this.$refs.imageInput.click()
    },
    
    // 触发视频上传
    triggerVideoUpload() {
      this.$refs.videoInput.click()
    },
    
    // 处理图片选择
    handleImageChange(e) {
      const files = Array.from(e.target.files)
      if (!files.length) return
      
      const remainingSlots = this.imageLimit - this.imageList.length
      if (files.length > remainingSlots) {
        this.$message.error(`最多还能上传${remainingSlots}张图片`)
        return
      }
      
      files.slice(0, remainingSlots).forEach(file => {
        if (this.validateFile(file, this.imageFileType, this.fileSize, '图片')) {
          this.uploadFile(file, 'image')
        }
      })
      
      // 清空input，允许重复选择相同文件
      this.$refs.imageInput.value = ''
    },
    
    // 处理视频选择
    handleVideoChange(e) {
      const files = Array.from(e.target.files)
      if (!files.length) return
      
      const remainingSlots = this.videoLimit - this.videoList.length
      if (files.length > remainingSlots) {
        this.$message.error(`最多还能上传${remainingSlots}个视频`)
        return
      }
      
      files.slice(0, remainingSlots).forEach(file => {
        if (this.validateFile(file, this.videoFileType, this.videoSize, '视频')) {
          this.uploadFile(file, 'video')
        }
      })
      
      // 清空input
      this.$refs.videoInput.value = ''
    },
    
    // 文件验证
    validateFile(file, allowedTypes, maxSize, fileTypeName) {
      const extension = file.name.substring(file.name.lastIndexOf('.') + 1)
      const type = file.type.split('/')[1] || ''
      
      const isTypeValid = allowedTypes.some(t => 
        file.type.includes(t) || extension.includes(t)
      )
      
      if (!isTypeValid) {
        this.$message.error(`请上传${allowedTypes.join('/')}格式的${fileTypeName}!`)
        return false
      }
      
      const isSizeValid = file.size / 1024 / 1024 < maxSize
      if (!isSizeValid) {
        this.$message.error(`${fileTypeName}大小不能超过${maxSize}MB!`)
        return false
      }
      
      return true
    },
    
    // 上传文件
    uploadFile(file, type) {
      // 创建临时预览URL
      const previewUrl = URL.createObjectURL(file)
      
      // 添加到列表显示上传状态
      const fileItem = {
        name: file.name,
        url: previewUrl,
        type: type,
        status: 'uploading',
        rawFile: file
      }
      
      if (type === 'image') {
        this.imageList.push(fileItem)
      } else {
        this.videoList.push(fileItem)
      }
      
      this.uploadingCount++
      this.$emit('upload-start')
      
      const formData = new FormData()
      formData.append('file', file)
      
      // 添加额外参数
      Object.keys(this.data).forEach(key => {
        formData.append(key, this.data[key])
      })
      
      request({
        url: this.action,
        method: 'post',
        data: formData,
        headers: {
          'Content-Type': 'multipart/form-data',
          'Authorization': 'Bearer ' + getToken()
        }
      }).then(response => {
        if (response.code === 200) {
          // 更新为服务器返回的URL
          fileItem.url = response.url || response.data.url
          fileItem.status = 'success'
          
          // 释放预览URL
          URL.revokeObjectURL(previewUrl)
          
          this.emitInput()
          this.$message.success(`${file.name} 上传成功`)
        } else {
          this.handleUploadError(fileItem, response.msg || '上传失败')
        }
      }).catch(error => {
        this.handleUploadError(fileItem, error.message || '服务器错误')
      }).finally(() => {
        this.uploadingCount--
        if (this.uploadingCount === 0) {
          this.$emit('upload-end')
        }
      })
    },
    
    // 处理上传错误
    handleUploadError(fileItem, errorMsg) {
      fileItem.status = 'error'
      this.$message.error(`${fileItem.name} 上传失败: ${errorMsg}`)
      
      // 从列表中移除失败项
      setTimeout(() => {
        if (fileItem.type === 'image') {
          const index = this.imageList.findIndex(item => item.name === fileItem.name)
          if (index > -1) this.imageList.splice(index, 1)
        } else {
          const index = this.videoList.findIndex(item => item.name === fileItem.name)
          if (index > -1) this.videoList.splice(index, 1)
        }
      }, 2000)
    },
    
    // 删除文件
    handleDelete(file, type) {
      this.$confirm(`确定要删除该${type === 'image' ? '图片' : '视频'}吗?`, '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        if (type === 'image') {
          const index = this.imageList.findIndex(f => f.url === file.url)
          if (index > -1) {
            this.imageList.splice(index, 1)
          }
        } else {
          const index = this.videoList.findIndex(f => f.url === file.url)
          if (index > -1) {
            this.videoList.splice(index, 1)
          }
        }
        
        this.emitInput()
        this.$message.success('删除成功')
      }).catch(() => {
        this.$message.info('已取消删除')
      })
    },
    
    
    // 图片预览
    handlePictureCardPreview(file) {
      this.dialogImageUrl = file.url
      this.imageDialogVisible = true
    },
    
    // 触发input事件
    emitInput() {
      const value = {
        images: this.imageList
          .filter(item => item.status === 'success')
          .map(item => item.url.replace(this.baseUrl, '')),
        videos: this.videoList
          .filter(item => item.status === 'success')
          .map(item => item.url.replace(this.baseUrl, ''))
      }
      this.$emit('input', value)
    }
  }
}
</script>

<style scoped lang="scss">
.component-upload-media {
  .upload-area {
    margin-bottom: 15px;
  }
  
  .image-list, .video-list {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-top: 10px;
  }
  
  .image-item, .video-item {
    position: relative;
    border: 1px solid #eee;
    border-radius: 4px;
    overflow: hidden;
    
    &:hover .image-actions, &:hover .video-actions {
      opacity: 1;
    }
  }
  
  .image-item {
    width: 120px;
    height: 120px;
    
    img {
      width: 100%;
      height: 100%;
      object-fit: cover;
      cursor: pointer;
    }
  }
  
  .video-item {
    width: 200px;
    
    video {
      width: 100%;
      height: auto;
      max-height: 150px;
    }
  }
  
  .image-actions, .video-actions {
    position: absolute;
    top: 5px;
    right: 5px;
    background: rgba(0, 0, 0, 0.5);
    border-radius: 50%;
    width: 24px;
    height: 24px;
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 0;
    transition: opacity 0.3s;
    cursor: pointer;
    
    .el-icon-delete {
      color: white;
      font-size: 14px;
    }
  }
  
  .upload-progress {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    background: rgba(0, 0, 0, 0.7);
    color: white;
    font-size: 12px;
    padding: 2px 5px;
    text-align: center;
  }
}
</style>